package com.handinglian.common.shiro;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.handinglian.common.enums.LoginStateEnum;
import com.handinglian.common.enums.LoginTypeEnum;
import com.handinglian.common.exception.BizException;
import com.handinglian.common.utils.StringUtil;
import com.handinglian.employee.entity.UserInfo;
import com.handinglian.employee.service.UserInfoService;
import com.handinglian.system.entity.Role;
import com.handinglian.system.service.RoleService;
import com.handinglian.thirdparty.JiGuangAPiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Fly
 * @Description
 * @Date Created in 9:20 2017/8/31
 * @Modified by
 */
@Slf4j
public class SystemAuthorizingRealm extends AuthorizingRealm {

    @Lazy
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private JiGuangAPiService jiGuangAPiService;



    /**
     * 认证回调函数, 登录时调用 设置了authc才会进入
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        // 校验用户名密码
        UserInfo userInfo = userInfoService.loadUserByJobNum(token.getUsername());
        if (ObjectUtil.isNull(userInfo)){
            return null;
        }

        if (token.getLoginType().equals(LoginTypeEnum.PC.getKey())){
            if (StringUtil.isBlank(userInfo.getDataList())){
                throw new AuthenticationException(BizException.NOT_ADMIN);
            }
            if (userInfo.getLoginState().equals(LoginStateEnum.DISABLE.getKey())){
                throw new AuthenticationException(BizException.NO_ADMIN_LOGIN_PERMISSION);
            }
        }

        //如果身份认证验证成功，返回一个AuthenticationInfo实现；
        SimpleAuthenticationInfo ai = new SimpleAuthenticationInfo(new Principal(userInfo), userInfo.getPassword(), getName());
        ai.setCredentialsSalt(ByteSource.Util.bytes(userInfo.getSalt())); //盐是用户名+随机数
        return ai;
    }

    @Override
    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info){
        super.assertCredentialsMatch(token, info);

        UsernamePasswordToken passwordToken = (UsernamePasswordToken) token;
        UserInfo userInfo = userInfoService.loadUserByJobNum(passwordToken.getUsername());

        if (StrUtil.isBlank(passwordToken.getPushId())){
            return;
        }
        if (StrUtil.isBlank(userInfo.getPushId())){
            userInfo.setPushId(passwordToken.getPushId());
            userInfoService.updateUserInfo(userInfo);
            return;
        }
        if (!userInfo.getPushId().equals(passwordToken.getPushId())){
            try {
                jiGuangAPiService.singleLoginPush(userInfo.getPushId());
            } catch (IOException e) {
                log.error("极光推送失败！",e);
            }
            userInfo.setPushId(passwordToken.getPushId());
            userInfoService.updateUserInfo(userInfo);
        }
    }



    /**
     * 获取权限授权信息，如果缓存中存在，则直接从缓存中获取，否则就重新获取， 登录成功后调用
     */
    @Override
    protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            return null;
        }
        //实际项目中这里可以设置缓存，从缓存中读取
        return doGetAuthorizationInfo(principals);
    }
    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        Principal principal = (Principal) getAvailablePrincipal(principals);

        UserInfo user = userInfoService.loadUserByJobNum(principal.getJobNum());

        if (user != null) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            List<com.handinglian.system.entity.Permission> permissions = userInfoService.inquirePermissionList(user.getJobNum());
            List<String> permissionStr = permissions.stream().map(permission -> permission.getPermission()).collect(Collectors.toList());
            info.addStringPermissions(permissionStr);

            Role role = roleService.getByUserId(user.getUserId());
            if (Objects.isNull(role)){
                throw new AuthenticationException("该人员尚无角色");
            }
            info.addRole(role.getRoleName());
            return info;
        } else {
            return null;
        }
    }

    @Override
    public boolean isPermitted(PrincipalCollection principals, Permission permission) {
        authorizationValidate(permission);
        return super.isPermitted(principals, permission);
    }

    @Override
    protected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {
        if (permissions != null && !permissions.isEmpty()) {
            for (Permission permission : permissions) {
                authorizationValidate(permission);
            }
        }
        return super.isPermittedAll(permissions, info);
    }

    /**
     * 授权验证方法
     * @param permission*/

    private void authorizationValidate(Permission permission){
        // 模块授权预留接口
    }

}
